Getting Started
{box} is an R package that released its very first v1.0.0 version on CRAN on February 2021. So, before we dive deeper, install {box} from CRAN first:
install.packages("box")or you can install the development version from R-universe:
install.packages('box', repos = 'https://klmr.r-universe.dev')Preferably, for the later chapters which involves the {carrier} Rust package, you’ll need the following forked version of this package, considering that the patches under the fork hasn’t made {box} upstream yet, which you can import {box}-{carrier} modules as you do with importing R packages and local modules. To install, do the following:
# Install the package through GitHub
# This needs compilation BTW
# Configure the following requirements
# Like Rtools and some toolchains
# To build the package
# install.packages('pak')
pak::pak(
"joshuamarie/box@feature/carrier-module-support"
)Why Box
For a long time, most R users compose their R codes in an R package or just a local collection of R scripts and sometimes with a deep nested directory. The reusability is rather not that granular: you going to have to use library() to load R packages and source() to read R codes within and between scripts. As discussed in the introduction, they are mostly a problem in management, most especially when you code gets larger and larger. And as you can see, there’s 2 functions you’re going to use and there’s no singular solution for an easy and ergonomic reusability.
That’s why {box} R package is recommended for these because it brings and simplifies modular programming in R for us. As described in its official documentation, it provides two key benefits:
It facilitates modular code writing by treating files and folders as independent, nestable modules, so you don’t need to wrap reusable code into packages.
It introduces a more powerful, less error-prone syntax for importing code from packages or modules, enabling explicit control over what names to import and restricting their scope.
With {box}, R users (or useRs) can take advantage of a modern (and correct) module system approach in R.
Understanding {box} package functionality
Before starting, you need to understand the field of functions offered by this package first.
Writing modules
To write modules with {box} is like writing an R package without the need to switch to other R projects with special package annotation and few boilerplates.
You can treat modules like packages. You can take advantage of this package to make your package prototype, before converting this into an actual package. On the recent development of {carrier} in 2026, you can make a package out of those modules with it.
Here are the few primary functions to be used when writing modules with {box}:
box::use()box::file()box::name()box::register_s3_method()mod-hooks: Hooks for module events (see for more details)- Miscellaneous: Roxygen2 documentation, which is beneficial in writing documentation for the R code under the module.
Module import / usage
Not just local modules, this also includes R packages.
Historically, box::use() is initially an alternative approach to import R packages.
{box} leverages R’s non-standard evaluation (NSE), by writing an expression as if they exist (only in different context). With {box}, you can refer R packages like list objects, then the brackets utilizes the “subset” functionality in R that extracts the exported namespaces: not through numbers and string, but through a literal name. No mapping and programmatic approach, aside from calling a name of the module with box::name(), you have to be explicit by naming the imports.
Understanding Module Paths and Root Directory
Before proceeding to the next step: importation, one crucial aspect of using {box} is understanding how it locates and imports modules. The package uses a root directory concept to resolve module paths:
Root Directory: By default,
box::file()searches for modules starting from your project’s root directory. Exceedingly,box::file()is also used to search the path within the script file you are working with.Module Path Resolution:
Paths starting with
./, e.g../module/file, are relative to the current filePaths without leading dots, e.g.
module/file, are relative to the root directoryPaths starting with
../are relative to the parent directory of the current fileForward slashes (
/) are used, even on Windows
Further explanations in chapters 2 to 3.
Knowing this helps streamline module management with {box}.
Basic Usage Example
Let’s start with examples. Remember that modules are objects after script files, folders / subfolders, or packages are loaded by box::use().
To get started, start a project, with a root directory name of modl/ (a short abbreviation of “module”), then create a script name mod.r / mod.R in the directory from the assumed directory structure:
# modl/
# ├── mod.rAfter creating mod.r / mod.R script, then try copy this code:
box::use(
stats[lm]
)
fit_and_predict = function (data, formula, ...)
lm(formula, data, ...)and then save the script. After you save the following script, you can now import mod as a module:
box::use(./mod)There’s no .r suffix, the name after / refers to a callable module in a form of a directory or an R script. Again, no need to quote the arguments in box::use(), unlike library() which you are allowed to import packages with quotes. After all, {box} package leverages R’s NSE.
Let’s get deeper. How about this mod.r you just wrote found under much deeper subfolder or subdirectory? To call such script as a module, you are going 1 level deeper and call that subfolder/subdirectory name before /, then call the script. Let’s assume that this is the directory structure:
# modl/
# ├── folder1/
# │ ├──mod.r
# │ ├── ...this can get deeper To import the script as a module, do the following:
box::use(./folder1/mod)Now, you have your mod.r script saved into the current environment as an environment called module.
Once called, you may now reuse it according to the following:
mod$fit_and_predict(cars, dist ~ speed)Common Import Patterns
Now that you have written an R code, saved in a script called mod.r, you also learn to import it as a module. You can access its names through $ operator, but there are few (if not several) ways to import mod.r or qualify its names. Here are some typical module import scenarios:
Import an entire script / folder as a module:
box::use( ./mod )NoteInitializationNote: If it is a script, you can directly access the names inside
mod, i.e.mod$fobj. On the other hand, ifmodis a folder or a directory, you need a file called__init__.rthat qualifies the folder as a module, then you can access its names as what you did by importing a script, or else you have to qualify the scripts undermodfolder i.e../mod/.../.... See Chapter 3 for more details.Import specific script in a folder as a module:
box::use( ./mod/mod1 )Import specific objects inside a script or an
__init__.r-flavored folder being explicitly called as a module:box::use( ./mod[obj1, obj2] )If
modis a folder, it can have nested modules, or usually just R objects like functions.Putting an alias when importing
modscript / folder:box::use( md = ./mod )Rename an object within the index, which treats
modlike a list:box::use( ./mod[ob1 = obj1, ob2 = obj2] )NoteNote: You don’t really have to put aliases for all the imports:
box::use( ./mod[ob1 = obj1, obj2] )Import from folders / nested folders
box::use( ./mod/mod1, # From subdir/module.R ./folder/mod/mod1, # From deep/nested/module.R ./folder/mod/mod1[ob1 = obj1] )
This is what other programming languages are proposing you to do. Known programming languages like Python strongly enforces this. The tradeoff is that it requires verbose syntax but the cost is minimal compared to what other solutions has offered.
This will work if mod is a script, not a folder, unless it has an initialization file named __init__.r.
Troubleshooting Module Imports
These are trivial and common issues, and so the solutions are also trivial:
When the module is not found, simply:
Verify path is relative to root directory
Ensure file exists with
.R/.rextension
For resolving the path of the modules:
Missing required prefixes, e.g.
./, to import the local modules, and wrong syntax are invalid.box::use(modules) # Missing ./ box::use(\modules\my_module) # Wrong slashesNoteTo be discussed…It is important to know that you can import
modulesthroughbox::use()only ifmodulesis a package (this will be explain in Chapter 2).The
/is a division operator in R, butbox::use()parses it differently, where the left hand side is the relative directory and the right hand side is the module you are going to import.box::use(./modules/my_module) # Relative to current file box::use(modules/my_module) # Relative to root (if set)It is much better if you follow best Practices. One example is to use relative paths with
./for clarity, if not a package. Keep local module files in a dedicated directory. And then, follow some consistent naming conventions, e.g. minimize using special characters that R parses unconventionally like a variable name offn-1.
Common use of syntax
When using {box}, you are hereby using the package through box:: prefixes only. You are not allowed to attach {box} through library(), i.e. library(box), but this is the less of your worries since it is already automatically internally hard-coded.